package io.github.mayubao.kotlintest

import org.junit.Assert
import org.junit.Assert.*
import org.junit.Test

/**
 * 1.class constuctor
 * 2.what the init block init times?
 * 3.how to define different constructors in class
 * 4.how to difine abstract method in class
 * 5.how to define nested class in class
 *   nested class likes static inner class in java
 * 6.how to define inner class in class
 *   inner class likes non static inner class in java
 *
 */
class Day11_ClassTest{

    @Test
    fun testClassConstrutor(){
//        val user = User("mayubao", 25)
//        assertEquals(vval, "test")
//        assertNotNull(user)
        val userClass = UserClass(1, "github")
        userClass.getUser()
        assertNotNull(userClass)
    }

    @Test
    fun testClassInitBlock(){
        val userClass = UserClass(1, "github")
        userClass.getUser()
        assertNotNull(userClass)
    }


    @Test
    fun testClassTwoConstrutor(){
        val person = Person()
        println(person.toString())
        val person1 = Person(1)
        println(person1.toString())
        val person2 = Person(2, "github")
        println(person2.toString())
        assertNotNull(person)
    }


    @Test
    fun testAbstractClass(){
        var obj1 = Obj1()
        var obj2 = Obj2()
        obj1.f()
        obj2.f()
        assertNotNull(obj1)
    }

    @Test
    fun testNestedClass(){
        var result = Outer.Nested().foo()
        assertEquals(2, result)
    }

    @Test
    fun testNestedClassWithInitBlockLife(){
        Outer.Nested().foo()
        val result = Outer.Nested().foo()

        //       call method Outer.Nested().foo() twice and the log as follow:
        //==================================
//        Nested class init...
//        Nested class init...
        //==================================
        //it means class Nested like static inner class
        assertEquals(2, result)
    }

    @Test
    fun testInnerClass(){
        Outer().Inner().foo()
        var result = Outer().Inner().foo()
        assertEquals(1, result)
    }


    @Test
    fun testAnonymousInnerClass(){
        val result = Outer().setTestInterface(object : TestInterface{
            override fun test() {
                println("create the annonymous inner class...")
            }

        })
        assertNotNull(result)
    }


    class UserClass(val id : Int, val name : String){
        init{
            println("UserClass construtor init...")
        }
        fun getUser(){
            println("id--->>>${id}, name --->>>${name}")
        }
    }

    class Person{
        var id : Int = 0;
        var name : String = "";

        init{
            println("Person init block init...")
        }

        constructor(){
            println("Person construtor with no param init...")
        }

        constructor(id :Int){
            println("Person construtor with one param init...")
            this.id = id;
        }
        constructor(id :Int, name :String){
            println("Person construtor with two param init...")
            this.id = id;
            this.name = name;
        }

        override fun toString(): String {
            return "Person(id=$id, name='$name')"
        }

    }


    /**
     * ?? open symbol means what ?
     */
    open class Base{
        open fun f(){
            println("Base  open method f()...")
        }
    }

    abstract  class Derived : Base(){
        abstract override fun  f()
    }

    class Obj1 : Derived() {
        override fun f() {
            println("Obj1 implements abstract method f()...")
        }
    }

    class Obj2 : Derived() {
        override fun f() {
            println("Obj2 implements abstract method f()...")
        }
    }


    /**
     * define a simple outer class
     */
    class Outer{                //outer class
        private val bar : Int = 1
        init {
            println("Outer class init...")
        }
        class Nested{           //nested class
            init {
                println("Nested class init...")
            }
            fun foo() = 2
        }

        inner class Inner{
            init {
                println("Inner class init...")
            }

            fun foo() = bar
            fun innerTest(){
                println("Inner method innerTest...")
            }
        }

        fun setTestInterface(testInterface: TestInterface){
            testInterface.test()
        }

    }

    interface  TestInterface{
        fun test()
    }


}